/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Data;

import java.util.ArrayList;

/**
 *
 * @author rjimenez
 */
public class ValidacionesSemanticas {


    ListaError listaErrores;
    Tabla tablaSimbolos;

    public ValidacionesSemanticas() {

        this.listaErrores = new ListaError();
    }

    public ValidacionesSemanticas(Tabla tablaSimbolos) {
        this.tablaSimbolos = tablaSimbolos;
        this.listaErrores = tablaSimbolos.listaErrores;
    }

    public ListaError getListaErrores() {
        return listaErrores;
    }

    public void setListaErrores(ListaError listaErrores) {
        this.listaErrores = listaErrores;
    }

    public Tabla getTablaSimbolos() {
        return tablaSimbolos;
    }

    public void setTablaSimbolos(Tabla tablaSimbolos) {
        this.tablaSimbolos = tablaSimbolos;
    }
    
    


    public NodoValor validarOperacionAritmetica(NodoValor e1, Token op ,NodoValor e2)
    {
        NodoValor resultado;

        if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.DECIMAL, op);
        }
        else if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.DECIMAL, op);
        }
        else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.DECIMAL, op);
        }
        else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.ENTERO, op);
        }
        else
        {
            listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
            return resultado = new NodoValor(Tipos.ERRORTIPO, op);
        }
    }


    public NodoValor validarOperacionLogica(NodoValor e1, Token op ,NodoValor e2)
    {
        NodoValor resultado;

        if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else
        {
            listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
            return resultado = new NodoValor(Tipos.ERRORTIPO, op);
        }
    }
    
    public NodoValor validarOperacionCondicional(NodoValor e1, Token op ,NodoValor e2)
    {
        NodoValor resultado;

        if(e1.getTipo().compareTo(Tipos.BOOLEANO)==0 && e2.getTipo().compareTo(Tipos.BOOLEANO)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else
        {
            listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
            return resultado = new NodoValor(Tipos.ERRORTIPO, op);
        }
    }

    public NodoValor validarOperacionNot(NodoValor e1, Token op)
    {
        NodoValor resultado;

        if(e1.getTipo().compareTo(Tipos.BOOLEANO)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
        }
        else
        {
            listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos debe ser una expresion booleana");
            return resultado = new NodoValor(Tipos.ERRORTIPO, op);
        }
    }

    public NodoValor validarOperacionIgualacion(NodoValor e1, Token op ,NodoValor e2)
    {
        NodoValor resultado;

//        if(e1.getTipo().compareTo(e2.getTipo())==0)
//        {
//            return resultado = new NodoValor(e1.getTipo(), op);
//        }
//        else if(e1.getTipo().compareTo(Tipos.OBJETO)==0 && e2.getTipo().compareTo(Tipos.NULO)==0)
//        {
//            return resultado = new NodoValor(Tipos.OBJETO, op);
//        }
//        else if(e1.getTipo().compareTo(Tipos.NULO)==0 && e2.getTipo().compareTo(Tipos.OBJETO)==0)
//        {
//            return resultado = new NodoValor(Tipos.OBJETO, op);
//        }
//        else
//        {
//            listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
            return resultado = new NodoValor(Tipos.BOOLEANO, op);
//        }
    }

    public NodoValor validarOperacionMasMenos(NodoValor e1, Token op ,NodoValor e2)
    {
        NodoValor resultado;

        if(op.getLexema().compareTo("+")==0)
        {

            if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
            {
                return resultado = new NodoValor(Tipos.DECIMAL, op);
            }
            else if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
            {
                return resultado = new NodoValor(Tipos.DECIMAL, op);
            }
            else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
            {
                return resultado = new NodoValor(Tipos.DECIMAL, op);
            }
            else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
            {
                return resultado = new NodoValor(Tipos.ENTERO, op);
            }
            else if(e1.getTipo().compareTo(Tipos.CADENA)==0)
            {
                return resultado = new NodoValor(Tipos.CADENA, op);
            }
            else if(e2.getTipo().compareTo(Tipos.CADENA)==0)
            {
                return resultado = new NodoValor(Tipos.CADENA, op);
            }
            else if(e1.getTipo().compareTo(Tipos.CARACTER)==0)
            {
                return resultado = new NodoValor(Tipos.CADENA, op);
            }
            else if(e1.getTipo().compareTo(Tipos.CARACTER)==0)
            {
                return resultado = new NodoValor(Tipos.CADENA, op);
            }
            else
            {
                listaErrores.AgregarErrorSemantico(op, "La operacion no se puede realizar tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
                return resultado = new NodoValor(Tipos.ERRORTIPO, op);
            }

        }
        else
        {
            return validarOperacionAritmetica(e1, op, e2);
        }
    }

    public NodoValor validarOperacionCasteo(NodoValor e1,NodoValor e2)
    {
        NodoValor resultado;

        if(e1.getTipo().compareTo(Tipos.CADENA)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.CADENA, e1.getVal());
        }
        else if(e1.getTipo().compareTo(Tipos.CADENA)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.CADENA, e1.getVal());
        }
        else if(e1.getTipo().compareTo(Tipos.CADENA)==0 && e2.getTipo().compareTo(Tipos.BOOLEANO)==0)
        {
            return resultado = new NodoValor(Tipos.BOOLEANO, e1.getVal());
        }
        else if(e1.getTipo().compareTo(Tipos.ENTERO)==0 && e2.getTipo().compareTo(Tipos.DECIMAL)==0)
        {
            return resultado = new NodoValor(Tipos.ENTERO, e1.getVal());
        }
        else if(e1.getTipo().compareTo(Tipos.DECIMAL)==0 && e2.getTipo().compareTo(Tipos.ENTERO)==0)
        {
            return resultado = new NodoValor(Tipos.DECIMAL, e1.getVal());
        }
        else
        {
            listaErrores.AgregarErrorSemantico(e1.getVal(), "La operacion no se puede realizar el casteo tipos incompatibles entre un: "+e1.getTipo()+" y "+e2.getTipo());
            return resultado = new NodoValor(Tipos.ERRORTIPO, e1.getVal());
        }
    }

    public NodoValor validarTipoVariable(String ambito, Token variable)
    {
        String tipo = tablaSimbolos.obtenerTipoVariable(ambito, variable);
        NodoValor val = new NodoValor(tipo, variable);
        return val;
    }
    
    public NodoValor validarTipoPropiedadObjeto(String ambito, Token objeto, Token variable)
    {
        String tipo = tablaSimbolos.obtenerTipoPropiedadObjeto(ambito, objeto, variable);
        NodoValor val = new NodoValor(tipo, variable);
        return val;
    }
    
    public NodoValor validarTipoFuncionObjeto(String ambito, Token objeto, Token variable,String parametros)
    {
        String tipo = tablaSimbolos.obtenerTipoFuncionObjeto(ambito, objeto, variable,parametros);
        NodoValor val = new NodoValor(tipo, variable);
        return val;
    }
    
    public NodoValor validarTipoFuncion(String ambito,Token variable,String parametros)
    {
        String tipo = tablaSimbolos.obtenerTipoFuncion(ambito,variable,parametros);
        NodoValor val = new NodoValor(tipo, variable);
        return val;
    }
    
    public void validarCondicion(NodoValor exp)
    {
        
        String tipo = exp.getTipo();
        
        if(tipo.compareTo(Tipos.BOOLEANO)!=0)
        {
            listaErrores.AgregarErrorSemantico(exp.getVal(), "La condicion debe ser booleana.");
            
        }
        
    }
    
    public void validarDeclaracionVariables(String tipo, NodoValor exp)
    {
        if(exp!=null)
        {
            String tipoAsignacion = exp.getTipo();

            if(tipo.compareTo(Tipos.ENTERO)==0 || tipo.compareTo(Tipos.CADENA)==0|| tipo.compareTo(Tipos.DECIMAL)==0 ||tipo.compareTo(Tipos.BOOLEANO)==0 ||tipo.compareTo(Tipos.CARACTER)==0  )
            {
                if(tipo.compareTo(tipoAsignacion)!=0)
                {
                     listaErrores.AgregarErrorSemantico(exp.getVal(), "La asignacion no se puede realizar  tipos incompatibles entre un: "+tipo+" y "+exp.getTipo());
                }

            }
            else
            {
                if(tipoAsignacion.compareTo(Tipos.NULO)==0)
                {
                    
                }
                else if(tipoAsignacion.compareTo(tipo)==0)
                {

                }
                else
                {
                    listaErrores.AgregarErrorSemantico(exp.getVal(), "La asignacion no se puede realizar  tipos incompatibles entre un: "+tipo+" y "+exp.getTipo());
                }
            }
        
            
        }
    }
    
    public void validarAsignaciones(String ambito, ArrayList<Token> variables, NodoValor exp)
    {
        for(Token variable: variables)
        {
            NodoValor val = validarTipoVariable(ambito, variable);
            
            validarDeclaracionVariables(val.getTipo(), exp);
            
        }
    }
    
    public void validarAsignaciones(String ambito, Token variable, NodoValor exp)
    {        
        NodoValor val = validarTipoVariable(ambito, variable);            
        validarDeclaracionVariables(val.getTipo(), exp);           
        
    }
    

}
